package com.example.demo.service.impl

import com.example.demo.dao.*
import com.example.demo.dao.Tables.delete
import com.example.demo.dao.Tables.tCareLabels
import com.example.demo.dao.Tables.tDepts
import com.example.demo.dao.Tables.tMessages
import com.example.demo.dao.Tables.tNurseLevels
import com.example.demo.dao.Tables.tOperations
import com.example.demo.dao.Tables.tPatientCareLabelRefs
import com.example.demo.dao.Tables.tPatients
import com.example.demo.dao.Tables.tShiftPlans
import com.example.demo.dao.Tables.tShiftTypes
import com.example.demo.dbmodels.TOperation
import com.example.demo.service.BoardService
import com.example.demo.utils.GmrDatabase
import com.example.demo.utils.TimeUtils
import com.example.demo.utils.WebDatabase
import com.example.demo.vo.*
import com.example.demo.vo.board.*
import me.liuwj.ktorm.dsl.*
import me.liuwj.ktorm.entity.add
import me.liuwj.ktorm.entity.filter
import me.liuwj.ktorm.entity.find
import me.liuwj.ktorm.entity.toList
import org.apache.commons.lang3.StringUtils
import org.joda.time.DateTime
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.sql.Timestamp
import java.text.SimpleDateFormat
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.*


@Service
class BoardServiceImpl(
        @Autowired
        private val webDatabase: WebDatabase,
        @Autowired
        private val gmrDatabase: GmrDatabase
) : BoardService {

    private val logger = LoggerFactory.getLogger(BoardServiceImpl::class.java)

    override fun getScheduleVo(deptCode: String): ScheduleVo? {
        val scheduleVo = ScheduleVo()
        gmrDatabase.getDataBase().tPatients.filter {
            it.dept_code eq deptCode
        }.toList().let {
            scheduleVo.patientTotal = PatientVo().getListVo(it).size.toString()
            gmrDatabase.getDataBase().tDepts.find {
                it.code eq deptCode
            }.let {
                scheduleVo.deptName = it?.name
            }
        }

        gmrDatabase.getDataBase().tOperations.filter {
            it.dept_code eq deptCode
        }.toList().let {
            val operationVO = OperationVO().getOperationListVo(it)
            scheduleVo.operationVos =operationVO
        }


        gmrDatabase.getDataBase().tMessages.filter {
            it.dept_code eq deptCode
        }.toList().let {
            val message =MessageVo().getMessageVoList(it)
            scheduleVo.messageVos =message
        }

        val careLists = mutableListOf<CareList>()
        gmrDatabase.getDataBase().from(TCareLabelDao)
                .leftJoin(TPatientCareLabelRefDao, on = TCareLabelDao.label_code eq TPatientCareLabelRefDao.care_label_id)
                .leftJoin(TPatientDao, on = TPatientCareLabelRefDao.patient_id eq TPatientDao.cure_no)
                .select()
                .orderBy(TCareLabelDao.label_code.asc())
                .map { row ->
                    val name = row[TCareLabelDao.label_name]
                    val managerName = row[TPatientCareLabelRefDao.bed_code]
                    val carelabelId = row[TCareLabelDao.id]
                    val id = row[TPatientCareLabelRefDao.id]
                    val careList = CareList()
                    careList.careName = name
                    careList.bedCode = managerName
                    careList.careId = carelabelId
                    careList.id = id
                    careLists.add(careList)
                }
        val map = careLists.groupBy { it.careName }
        val bedList = mutableListOf<CareBedList>()
        map.forEach {
            val bed = CareBedList()
            bed.careName = it.key
            bed.bedCode = it.value
            bed.careLabelId = it.value[0].careId
            bed.id = it.value[0].id
            bedList.add(bed)
        }
        scheduleVo.bedList = bedList
        return scheduleVo
    }

    override fun getPatientList(deptCode: String, type: String?, sex: String?): List<PatientVo>? {
        val patientVoList = mutableListOf<PatientVo>()
        var nurseLevelVo: NurseLevelVo? = null
        var doctorVo: DoctorVo? = null
        var nurseVo: NurseVo? = null
        gmrDatabase.getDataBase().from(TPatientDao)
                .leftJoin(TNurseLevelDao, on = TPatientDao.nurse_level_code eq TNurseLevelDao.level_code)
                .leftJoin(TDoctorDao, on = TPatientDao.doctor_code eq TDoctorDao.code)
                .leftJoin(TNurseDao, on = TPatientDao.nurse_code eq TNurseDao.code)
                .select()
                .where { TPatientDao.dept_code eq deptCode }
                .forEach {
                    val patientVo = PatientVo().getVo(it)
                    nurseLevelVo = NurseLevelVo().getVoQuery(it)
                    doctorVo = DoctorVo().getDoctorVo(it)
                    nurseVo = NurseVo().getDoctorVo(it)
                    patientVo.nurseLevel = nurseLevelVo
                    patientVo.doctorVo = doctorVo
                    patientVo.nurseVo = nurseVo
                    patientVoList.add(patientVo)
                }
        if ((StringUtils.isNotEmpty(type)) || (StringUtils.isNotEmpty(sex))) {
            val patientList = mutableListOf<PatientVo>()
            patientVoList.forEach {
                if (type != "") {
                    if (it.nurseLevel?.level_type == type?.toInt()) {
                        patientList.add(it)
                    }
                }
                if (sex != "") {
                    if (it.sex == sex?.toInt()) {
                        patientList.add(it)
                    }
                }
            }
            return patientList
        }
        return patientVoList
    }

    override fun getPatientInfo(patientId: String): BedInfoVo? {
        val bedInfoVo = BedInfoVo()
        var patientVo: PatientVo? = null
        var doctorVo: DoctorVo? = null
        var nurseVo: NurseVo? = null
        var deptVo: DeptVo? = null
        var nurseLevelVo: NurseLevelVo? = null
        val patientCareLabelRefVoList = mutableListOf<PatientCareLabelRefVo>()
        var patientCareLabelRefVo: PatientCareLabelRefVo? = null
        gmrDatabase.getDataBase().from(TPatientDao)
                .leftJoin(TDoctorDao, on = TPatientDao.doctor_code eq TDoctorDao.code)
                .leftJoin(TNurseDao, on = TPatientDao.nurse_code eq TNurseDao.code)
                .leftJoin(TPatientCareLabelRefDao, on = TPatientDao.cure_no eq TPatientCareLabelRefDao.patient_id)
                .leftJoin(TDeptDao, on = TPatientDao.dept_code eq TDeptDao.code)
                .leftJoin(TNurseLevelDao, on = TPatientDao.nurse_level_code eq TNurseLevelDao.level_code)
                .select()
                .where { (TPatientDao.cure_no eq patientId) }
                .forEach {
                    patientVo = PatientVo().getVo(it)
                    doctorVo = DoctorVo().getDoctorVo(it)
                    nurseVo = NurseVo().getDoctorVo(it)
                    deptVo = DeptVo().getDeptVo(it)
                    nurseLevelVo = NurseLevelVo().getVoQuery(it)
                    patientCareLabelRefVo = PatientCareLabelRefVo().getVo(it)
                    patientCareLabelRefVo?.let {
                        patientCareLabelRefVoList.add(it)
                    }
                }

        bedInfoVo.patientVo = patientVo
        bedInfoVo.doctorVo = doctorVo
        bedInfoVo.nurseVo = nurseVo
        bedInfoVo.deptvo = deptVo
        bedInfoVo.nurseLevel = nurseLevelVo
        bedInfoVo.patientCareLabelRefVo = patientCareLabelRefVoList
        val careLabelVoList = mutableListOf<CareLabelVo>()
        bedInfoVo.patientCareLabelRefVo?.forEach { patientCareLabelRefVo ->
            gmrDatabase.getDataBase().tCareLabels.find {
                it.label_code eq patientCareLabelRefVo.care_label_id.toString()
            }?.let {
                val careLabelVo = CareLabelVo().getCareLabelVo(it)
                careLabelVo?.let {
                    careLabelVoList.add(it)
                }
            }
        }
        bedInfoVo.bedSideCareLabelVo = careLabelVoList
        return bedInfoVo
    }

    override fun editPatientInfo(cureNo: String, outlayType: String?, mobile: String?, doctorCode: String?, nurseCode: String?, deptCode: String?, nurseLevel: String?, inTimer: String?): Int? {
        val tPatient = gmrDatabase.getDataBase().tPatients.find { it.cure_no eq cureNo } ?: return null
        outlayType?.let { tPatient.outlay_type = it }
        mobile?.let { tPatient.mobile = it }
        doctorCode?.let { tPatient.doctor_code = it }
        nurseCode?.let { tPatient.nurse_code = nurseCode }
        deptCode?.let { tPatient.dept_code = deptCode }
        nurseLevel?.let { tPatient.nurse_level_code = nurseLevel }
        inTimer?.let {
            val str = "$it 12:30"
            val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
            val dateTime = LocalDateTime.parse(str, formatter)
            tPatient.in_time = dateTime
        }
        return tPatient.flushChanges()
    }

    override fun getShiftPlanInfo(deptCode: String, type: String): ShiftPlanInfo? {
        gmrDatabase.getDataBase().tShiftPlans.filter {
            it.dept_code eq deptCode
        }.filter {
            it.staff_type eq type.toInt()
        }.toList().let {
            val shiftPlanInfo = ShiftPlanInfo()
            shiftPlanInfo.shiftPlanVo = ShiftPlanVo().getShiftPlanInVo(it)
            gmrDatabase.getDataBase().tShiftTypes.toList().let {
                shiftPlanInfo.shiftTypeVo = ShiftTypeVo().getShiftTypeVoList(it)
            }
            return shiftPlanInfo
        }
    }

    override fun getNurseLevel(): List<NurseLevelVo>? {
        gmrDatabase.getDataBase().tNurseLevels.toList().let {
            return NurseLevelVo().getNurseLevelVo(it)
        }
    }

    override fun addNurseLevel(levelName: String?, bgColor: String?, fontColor: String?): Int? {
        gmrDatabase.getDataBase().insertAndGenerateKey(TNurseLevelDao) {
            set(it.level_name, levelName)
            set(it.bg_color, bgColor)
            set(it.font_color, fontColor)
            set(it.update_time, TimeUtils.getNowTimer())
        }.let {
            return it.toString().toInt()
        }
    }

    override fun deteleNurseLevel(labeleId: String): Int? {
        val employee = gmrDatabase.getDataBase().tNurseLevels.find { it.id eq labeleId.toInt() } ?: return null
        employee.delete().let { return it }
    }

    override fun getEditNurseLevel(id: Int, bgColor: String, fontColor: String, levelName: String): Int? {
        gmrDatabase.getDataBase().update(TNurseLevelDao) {
            set(it.bg_color, bgColor)
            set(it.font_color, fontColor)
            set(it.level_name, levelName)
            where {
                it.id eq id
            }
        }.let {
            return it
        }
    }

    override fun getCareLevelList(): List<CareLabelVo>? {
        gmrDatabase.getDataBase().tCareLabels.toList().let {
            return CareLabelVo().getCareLabelVoList(it)
        }
    }

    override fun getEditCareLevel(id: Int, bgColor: String, fontColor: String, labelName: String): Int? {
        gmrDatabase.getDataBase().update(TCareLabelDao) {
            set(it.bg_color, bgColor)
            set(it.font_color, fontColor)
            set(it.label_name, labelName)
            where {
                it.id eq id
            }
        }.let {
            return it
        }
    }

    override fun addNurseLevelLabel(bgColor: String, fontColor: String, levelName: String, labelCat:String): Int? {

        gmrDatabase.getDataBase().insertAndGenerateKey(TCareLabelDao) {
            set(it.label_name, levelName)
            set(it.label_cat, labelCat)
            set(it.bg_color, bgColor)
            set(it.font_color, fontColor)
            set(it.update_time, TimeUtils.getNowTimer())
        }.let {
            return it.toString().toInt()
        }
    }

    override fun deleteNurseLevelLabel(labeleId: String): Int? {
        val employee = gmrDatabase.getDataBase().tCareLabels.find { it.id eq labeleId.toInt() } ?: return null
        employee.delete().let { return it }
    }

    override fun addCareLevel(patientId: String?, careLabelId: String, bedCode: String?, deptCode: String?): Int? {
        val d = Date()
        val sdf = SimpleDateFormat("yyyy-MM-dd kk:mm:ss ")
        gmrDatabase.getDataBase().insertAndGenerateKey(TPatientCareLabelRefDao) {
            set(it.patient_id, patientId)
            set(it.care_label_id, careLabelId)
            set(it.bed_code, bedCode)
            set(it.dept_code, deptCode)
            set(it.update_time, sdf.format(d))
        }.let {
            return it.toString().toInt()
        }
    }

    override fun deleteCareLevel(id:String): Int? {
        val employee = gmrDatabase.getDataBase().tPatientCareLabelRefs.find { it.id eq id.toInt() } ?: return null
        employee.delete().let { return it }
    }

    override fun getMessageList(patientId: String): List<MessageVo>? {
        gmrDatabase.getDataBase().tMessages.filter {
            it.patient_id eq patientId
        }.toList().let {
            return MessageVo().getMessageVoList(it)
        }
    }

    override fun addMessage(patientId: String?, title: String?, context: String?, imgurl: String?, fileurl: String?, type: String?): Int? {
        val d = Date()
        val sdf = SimpleDateFormat("yyyy-MM-dd kk:mm:ss ")
        gmrDatabase.getDataBase().insertAndGenerateKey(TMessageDao) {
            set(it.title, title)
            set(it.patient_id, patientId)
            set(it.context, context)
            set(it.imgurl, imgurl)
            set(it.fileurl, fileurl)
            set(it.type, type)
            set(it.time, sdf.format(d))
        }.let {
            return it.toString().toInt()
        }
    }

    override fun addOperations(deptCode: String,patientId: String, opDoc:String, opName:String,ansDoc1:String, ansDoc2:String
                               , assistDoc1:String, assistDoc2:String, assistDoc3:String, cirNurse1:String,cirNurse2:String,scrNurse1:String,scrNurse2:String,
                               opTime:String, opDate:String): Int {
        val str = "$opDate 12:30"
        val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
        val dateTime = LocalDateTime.parse(str, formatter)
        val data = TOperation()
        data.dept_code = deptCode
        data.patient_code = patientId
        data.op_doc = opDoc
        data.op_name = opName
        data.ans_doc1 = ansDoc1
        data.asn_doc2 = ansDoc2
        data.assist_doc1 = assistDoc1
        data.assist_doc2 = assistDoc2
        data.assist_doc3 = assistDoc3
        data.cir_nurse1 = cirNurse1
        data.cir_nurse2 = cirNurse2
        data.scr_nurse1 =scrNurse1
        data.scr_nurse2 = scrNurse2
        data.op_time = opTime
        data.op_date = dateTime
        gmrDatabase.getDataBase().tOperations.add(data)
        return 0
    }


}